package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
)

type ChatProtocol struct {
	Id     uint16
	Length uint32
	Data   []byte
}

const (
	DefaultHeadLength = 6

	ProtocolId uint16 = 0x0001 // v1 protocol version
)

// Encode
func Encode(data []byte) ([]byte, error) {
	result := make([]byte, 0)

	buffer := bytes.NewBuffer(result)

	if err := binary.Write(buffer, binary.BigEndian, ProtocolId); err != nil {
		s := fmt.Sprintf("Pack version error , %v", err)
		return nil, errors.New(s)
	}
	dataLen := uint32(len(data))
	if err := binary.Write(buffer, binary.BigEndian, dataLen); err != nil {
		s := fmt.Sprintf("Pack datalength error , %v", err)
		return nil, errors.New(s)
	}
	if dataLen > 0 {
		if err := binary.Write(buffer, binary.BigEndian, data); err != nil {
			s := fmt.Sprintf("Pack data error , %v", err)
			return nil, errors.New(s)
		}
	}

	return buffer.Bytes(), nil
}

// Decode
func Decode(rawConn net.Conn) (*ChatProtocol, error) {
	newPackage := ChatProtocol{}

	headData := make([]byte, DefaultHeadLength)
	n, err := io.ReadFull(rawConn, headData)
	if n != DefaultHeadLength {
		return nil, err
	}

	// parse protocol header
	bytesBuffer := bytes.NewBuffer(headData)
	_ = binary.Read(bytesBuffer, binary.BigEndian, &newPackage.Id)
	_ = binary.Read(bytesBuffer, binary.BigEndian, &newPackage.Length)

	if newPackage.Length < 1 {
		return &newPackage, nil
	}

	data := make([]byte, newPackage.Length)
	dataNum, err2 := io.ReadFull(rawConn, data)
	if uint32(dataNum) != newPackage.Length {
		s := fmt.Sprintf("read data error, %v", err2)
		return nil, errors.New(s)
	}

	newPackage.Data = data
	return &newPackage, nil
}
